package cn.flying.base.core.configuration;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.RemovalListener;

/**
 * @description: 自定义配置
 * @author: lvyong
 * @date: 2023年05月26日 16:34
 * @version: 1.0
 */
@EnableAsync
@EnableCaching
@Configuration
public class FlyingAutoConfiguration {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 定时任务的线程池
     *
     * @return
     */
    @Bean("threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(10);
        taskExecutor.setMaxPoolSize(50);
        taskExecutor.setQueueCapacity(200);
        taskExecutor.setKeepAliveSeconds(60);
        taskExecutor.setThreadNamePrefix("flying-task-");
        taskExecutor.setAwaitTerminationSeconds(60);
        return taskExecutor;
    }

    /**
     * 相当于在构建LoadingCache对象的时候 build()方法中指定过期之后的加载策略方法
     * 必须要指定这个Bean，refreshAfterWrite=60s属性才生效
     *
     * @return
     */
    @Bean
    public CacheLoader<String, Object> cacheLoader() {
        CacheLoader<String, Object> cacheLoader = new CacheLoader<String, Object>() {
            @Override
            public Object load(String key) throws Exception {
                return null;
            }

            // 重写这个方法将oldValue值返回回去，进而刷新缓存
            @Override
            public Object reload(String key, Object oldValue) throws Exception {
                return oldValue;
            }
        };
        return cacheLoader;
    }

    /**
     * 本地caffeine缓存配置
     *
     * @return
     */
    @Bean
    public Cache<String, Object> caffeineCache() {
        Cache<String, Object> cache = Caffeine.newBuilder()
                //初始的缓存空间大小
                .initialCapacity(100)
                //缓存的最大条数
                .maximumSize(100000)
                //最后一次写入后经过固定时间过期
                .expireAfterWrite(4, TimeUnit.SECONDS)
                //最后一次写入或访问后经过固定时间过期
                .expireAfterAccess(10, TimeUnit.SECONDS)
                //创建缓存或者最近一次更新缓存后经过固定的时间间隔，刷新缓存 最后一次写入后经过固定时间过期
                .refreshAfterWrite(6, TimeUnit.SECONDS)
                .recordStats()
                //设置缓存的移除通知
                .removalListener(new RemovalListener<String, Object>() {
                    @Override
                    public void onRemoval(String key, Object value, RemovalCause cause) {
                        logger.info("Key：【{}】，Value：【{}】was removed！原因： ({})", key, value, cause);
                    }
                })
                .build(cacheLoader());
        return cache;
    }
}
